// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ash/cert_provisioning/cert_provisioning_test_helpers.h"

#include "base/test/gmock_callback_support.h"
#include "base/time/time.h"
#include "chrome/browser/ash/profiles/profile_helper.h"
#include "chrome/test/base/testing_browser_process.h"
#include "net/test/cert_builder.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/types/optional.h"

using base::test::RunOnceCallback;
using testing::_;
using testing::Invoke;

namespace ash {
namespace cert_provisioning {

//================ CertificateHelperForTesting =================================

// Generated by chrome/test/data/policy/test_certs/create_test_certs.sh
const char kFakeCertificate[] = R"(-----BEGIN CERTIFICATE-----
MIIDJzCCAg+gAwIBAgIBATANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxyb290
X2NhX2NlcnQwHhcNMjAwMjI1MTUyNTU2WhcNMzAwMjIyMTUyNTU2WjAUMRIwEAYD
VQQDDAkxMjcuMC4wLjEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDW
druvpaJovmyWzIcjtsSk/lp319+zNPSYGLzJzTeEmnFoDf/b89ft6xR1NIahmvVd
UHGOMlzgDKnNkqWw+pgpn6U8dk+leWnwlUefzDz7OY8qXfX29Vh0m/kATQc64lnp
rX19fEi2DOgH6heCQDSaHI/KAnAXccwl8kdGuTEnvdzbdHqQq8pPGpEqzC/NOjk7
kDNkUt0J74ZVMm4+jhVOgZ35mFLtC+xjfycBgbnt8yfPOzmOMwXTjYDPNaIy32AZ
t66oIToteoW5Ilg+j5Mto3unBDHrw8rml3+W/nwHuOPEIgBqLQFfWtXpuX8CbcS6
SFNK4hxCJOvlzUbgTpsrAgMBAAGjgYAwfjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQW
BBRDEl1/2pL5LtKnpIly+XCj3N6MwDAfBgNVHSMEGDAWgBQrwVEnUQZlX850A2N+
URfS8BxoyzAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0RBAgw
BocEfwAAATANBgkqhkiG9w0BAQsFAAOCAQEAXZd+Ul7GUFZPLSiTZ618hUI2UdO0
7rtPwBw3TephWuyEeHht+WhzA3sRL3nprEiJqIg5w/Tlfz4dsObpSU3vKmDhLzAx
HJrN5vKdbEj9wyuhYSRJwvJka1ZOgPzhQcDQOp1SqonNxLx/sSMDR2UIDMBGzrkQ
sDkn58N5eWm+hZADOAKROHR47j85VcsmYGK7z2x479YzsyWyOm0dbACXv7/HvFkz
56KvgxRaPZQzQUg5yuXa21IjQz07wyWSYnHpm2duAbYFl6CTR9Rlj5vpRkKsQP1W
mMhGDBfgEskdbM+0agsZrJupoQMBUbD5gflcJlW3kwlboi3dTtiGixfYWw==
-----END CERTIFICATE-----)";

CertificateHelperForTesting::CertificateHelperForTesting(
    platform_keys::MockPlatformKeysService* platform_keys_service)
    : platform_keys_service_(platform_keys_service) {
  template_cert_ = CreateSingleCertificateFromBytes(kFakeCertificate,
                                                    sizeof(kFakeCertificate));
  DCHECK(template_cert_);
  EXPECT_CALL(*platform_keys_service_, GetCertificates)
      .WillRepeatedly(
          Invoke(this, &CertificateHelperForTesting::GetCertificates));
}

CertificateHelperForTesting::~CertificateHelperForTesting() = default;

void CertificateHelperForTesting::GetCertificates(
    chromeos::platform_keys::TokenId token_id,
    platform_keys::GetCertificatesCallback callback) {
  auto result = std::make_unique<net::CertificateList>();
  *result = cert_list_;
  std::move(callback).Run(std::move(result),
                          chromeos::platform_keys::Status::kSuccess);
}

scoped_refptr<net::X509Certificate> CertificateHelperForTesting::AddCert(
    CertScope cert_scope,
    const absl::optional<CertProfileId>& cert_profile_id,
    chromeos::platform_keys::Status status,
    base::Time not_valid_before,
    base::Time not_valid_after) {
  net::CertBuilder cert_builder(template_cert_->cert_buffer(),
                                /*issuer=*/nullptr);
  cert_builder.SetValidity(not_valid_before, not_valid_after);
  auto cert = cert_builder.GetX509Certificate();

  EXPECT_CALL(
      *platform_keys_service_,
      GetAttributeForKey(
          GetPlatformKeysTokenId(cert_scope),
          chromeos::platform_keys::GetSubjectPublicKeyInfo(cert),
          chromeos::platform_keys::KeyAttributeType::kCertificateProvisioningId,
          _))
      .WillRepeatedly(RunOnceCallback<3>(cert_profile_id, status));

  cert_list_.push_back(cert);
  return cert;
}

scoped_refptr<net::X509Certificate> CertificateHelperForTesting::AddCert(
    CertScope cert_scope,
    const absl::optional<CertProfileId>& cert_profile_id) {
  base::Time not_valid_before = base::Time::Now() - base::Days(1);
  base::Time not_valid_after = base::Time::Now() + base::Days(365);
  return AddCert(cert_scope, cert_profile_id,
                 chromeos::platform_keys::Status::kSuccess, not_valid_before,
                 not_valid_after);
}

scoped_refptr<net::X509Certificate> CertificateHelperForTesting::AddCert(
    CertScope cert_scope,
    const absl::optional<CertProfileId>& cert_profile_id,
    chromeos::platform_keys::Status status) {
  base::Time not_valid_before = base::Time::Now() - base::Days(1);
  base::Time not_valid_after = base::Time::Now() + base::Days(365);
  return AddCert(cert_scope, cert_profile_id, status, not_valid_before,
                 not_valid_after);
}

void CertificateHelperForTesting::ClearCerts() {
  cert_list_.clear();
}

const net::CertificateList& CertificateHelperForTesting::GetCerts() const {
  return cert_list_;
}

//================ ProfileHelperForTesting =====================================

namespace {
const char kTestUserEmail[] = "user@gmail.com";
const char kTestUserGaiaId[] = "test_gaia_id";
}  // namespace

ProfileHelperForTesting::ProfileHelperForTesting()
    : ProfileHelperForTesting(/*user_is_affiilated=*/false) {}

ProfileHelperForTesting::ProfileHelperForTesting(bool user_is_affiliated)
    : testing_profile_manager_(TestingBrowserProcess::GetGlobal()) {
  Init(user_is_affiliated);
}

ProfileHelperForTesting::~ProfileHelperForTesting() = default;

void ProfileHelperForTesting::Init(bool user_is_affiliated) {
  ASSERT_TRUE(testing_profile_manager_.SetUp());

  testing_profile_ =
      testing_profile_manager_.CreateTestingProfile(kTestUserEmail);
  ASSERT_TRUE(testing_profile_);

  auto test_account =
      AccountId::FromUserEmailGaiaId(kTestUserEmail, kTestUserGaiaId);
  user_ = fake_user_manager_.AddUserWithAffiliation(test_account,
                                                    user_is_affiliated);

  ProfileHelper::Get()->SetUserToProfileMappingForTesting(
      fake_user_manager_.GetPrimaryUser(), testing_profile_);
}

Profile* ProfileHelperForTesting::GetProfile() const {
  return testing_profile_;
}

user_manager::User* ProfileHelperForTesting::GetUser() const {
  return user_;
}

}  // namespace cert_provisioning
}  // namespace ash
